package com.csvc.business.cmdb.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csvc.business.cmdb.Constants;
import com.csvc.business.cmdb.service.ICmSynOrderService;
import com.csvc.commons.dto.MessageDto;
import com.csvc.commons.dto.WFMessageDto;
import com.csvc.repository.cmdb.domain.CmSynOrder;
import com.csvc.repository.cmdb.domain.MysqlInfo;
import com.csvc.repository.cmdb.domain.OraSegment;
import com.csvc.repository.cmdb.domain.OracleInfo;
import com.csvc.repository.cmdb.domain.Server;
import com.csvc.repository.cmdb.mapper.CmSynOrderMapper;
import com.csvc.repository.cmdb.mapper.MysqlInfoMapper;
import com.csvc.repository.cmdb.mapper.OraSegmentMapper;
import com.csvc.repository.cmdb.mapper.OracleInfoMapper;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author vincent zou
 * @since 2021-01-10
 */
@Service
@Slf4j
public class CmSynOrderServiceImpl extends ServiceImpl<CmSynOrderMapper, CmSynOrder> implements ICmSynOrderService {

	@Resource
	private CmSynOrderMapper cmSynOrderMapper;

	@Resource
	private OracleInfoMapper oracleInfoMapper;

	@Resource
	private MysqlInfoMapper mysqlInfoMapper;
	
	@Autowired
	private EmailService emailservice;
	
	@Resource
	private OraSegmentMapper oraSegmentMapper;

	@Override
	public boolean create(CmSynOrder cmSynOrder) {
		return super.save(cmSynOrder);
	}

	@Override
	public boolean remove(Long id) {
		return super.removeById(id);
	}

	@Override
	public boolean update(CmSynOrder cmSynOrder) {
		if (null == cmSynOrder.getId() || cmSynOrder.getId() < 0) {
			String busiNo = cmSynOrder.getBusiNo();
			QueryWrapper<CmSynOrder> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("busi_no", busiNo); // 等值查询
			CmSynOrder selectOne = cmSynOrderMapper.selectOne(queryWrapper);
			log.info("busi no : {}, selectOne:{}", busiNo, selectOne);
			cmSynOrder.setId(selectOne.getId());
		}

		return super.updateById(cmSynOrder);
	}

	@Override
	public boolean archiveOrder(WFMessageDto msg) {
        String busiNo = msg.getBusiNo();
    	CmSynOrder selectOne = getOrderByBusiNo(busiNo);
		
		log.info("busi no : {}, selectOne:{}", busiNo, selectOne);
		String subject = "order completion";
		MessageDto dto = transferToMessageDto(selectOne,msg,subject);
		emailservice.invoideNotifyRestAPI(dto);
		return super.updateById(selectOne);
	}
	
	//status 1 success 2 cancel 3 failure
	private MessageDto transferToMessageDto(CmSynOrder order,WFMessageDto msg,String subject) {
		MessageDto dto = new MessageDto();
		dto.setMediaType(1);
		dto.setSource("csvc");
		String[] mediaAddressList = order.getNotiList().split(",");
		log.info("WFMessageDto:{}",msg);
		log.info("mediaAddressList[0]:{}",mediaAddressList[0]);
		dto.setMediaAddressList(mediaAddressList);
		if(Constants.EXECUTION_SUCCESS.equals(msg.getCode())) {
			dto.setSubject(subject+"[SUCCESS]");
			order.setStatus(1);
			dto.setContent("kindly inform you that the order["+ msg.getBusiNo() +"] was completed successfully!");
		}else if (Constants.CANCEL_SUCCESS.equals(msg.getCode())){
			dto.setSubject(subject+"[CANCEL]");
			order.setStatus(3);
			dto.setContent(" cancel order["+ msg.getBusiNo() +"] successfully!");
		}else {
			order.setStatus(2);
			dto.setSubject(subject+"[FAILURE]");
			dto.setContent(" the order["+ msg.getBusiNo() +"] process failure! error info:"+msg.getMsg());
		}
		
		
		return dto;
	}

	@Override
	public CmSynOrder get(Long id) {
		return super.getById(id);
	}

	@Override
	public IPage<CmSynOrder> page(int current, int size, CmSynOrder cmSynOrder) {
		Page<CmSynOrder> page = new Page<>(current, size);
		LambdaQueryWrapper<CmSynOrder> wrapper = new LambdaQueryWrapper<>();
		// TODO 查询
		// TODO 排序
		return super.page(page, wrapper);
	}

	@Override
	public boolean putNotificationList(String contactway, String busiNo) {
		log.info("----->>contactway{},business No:{}", contactway, busiNo);
		List<CmSynOrder> cmSynOrders = getSameOrder(busiNo);
		CmSynOrder cmSynOrder = cmSynOrders.get(0);
		if (!StringUtils.isEmpty(busiNo)) {
			cmSynOrder.setNotiList(cmSynOrder.getNotiList() + "," + contactway);
			MessageDto dto = new MessageDto();
			dto.setMediaType(1);
			dto.setSource("csvc");
			String[] mediaAddressList = contactway.split(",");
			dto.setMediaAddressList(mediaAddressList);
			dto.setSubject("Same Order Exist Alert - busiNo["+busiNo+"]");
			dto.setContent("There is same with in-progress order["+cmSynOrder.getBusiNo() +"]! it will let you know when it complete.!");
			emailservice.invoideNotifyRestAPI(dto);
			log.info(" size:{}", cmSynOrderMapper.updateById(cmSynOrder));
		}
		return true;
	}

	@Override
	public CmSynOrder checkInclusiveConditions(String busiNo) {
		List<CmSynOrder> cmSynOrder = getSameOrder(busiNo);
		if (CollectionUtils.isEmpty(cmSynOrder))
			return null;
		return cmSynOrder.get(0);
	}

	private List<CmSynOrder> getSameOrder(String busiNo) {
		CmSynOrder selectOne = getOrderByBusiNo(busiNo);
		if (selectOne == null) {
			throw new RuntimeException(busiNo + " do not exist! ");
		}
		Map<String, Object> params = new HashMap<>();
		params.put("srcInsName", selectOne.getSrcInsName());
		params.put("destInsName", selectOne.getDestInsName());
		params.put("srcSchema", selectOne.getSrcSchema());
		params.put("destSchema", selectOne.getDestSchema());
		params.put("srcTables", selectOne.getSrcTables() + "%");
		params.put("busiNo", busiNo);
		log.info("-----------------------------{}", params);
		List<CmSynOrder> cmSynOrder = cmSynOrderMapper.qryOrders(params);

		log.info("---------------wwww--------------{}", cmSynOrder);
		return cmSynOrder;
	}

	private CmSynOrder getOrderByBusiNo(String busiNo) {
		log.info("----->>business No:{}", busiNo);
		QueryWrapper<CmSynOrder> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("busi_no", busiNo); // 等值查询
		CmSynOrder selectOne = cmSynOrderMapper.selectOne(queryWrapper);
		log.debug("result:{}", selectOne);
		return selectOne;
	}

	private void setSrcServerAndScript(CmSynOrder selectOne, Map<String, Object> map,String filename) {

		OracleInfo oracleinfo = getOracleInfo(selectOne.getSrcInsName());
		MysqlInfo mysqlinfo = getMysqlInfo(selectOne.getSrcInsName());
		if (null != oracleinfo) {
			Server server = new Server();
			server.setServer(oracleinfo.getHostIp());
			server.setUser("oracle");
			server.setPort(22);
			server.setPassword(oracleinfo.getOsPasswd());
			map.put("srcServer", server); // srcServer
			log.info("srcServer:{}", server);
			// Schema迁移
			String srcScript = "expdp \"userid='/ as sysdba'\" directory=exp_excel_dir schemas=source_schema dumpfile="+oracleinfo.getBackupDir()+"/"+filename+".dmp CONTENT=all";
			if (!StringUtils.isEmpty(selectOne.getSrcTables())) {
				// Table迁移
				srcScript = "expdp \"userid='/ as sysdba'\" directory=exp_excel_dir dumpfile="+oracleinfo.getBackupDir()+"/"+filename+".dmp tables=source_schema.table_name";
			}
			srcScript = srcScript.replaceAll("source_schema", selectOne.getSrcSchema()).replaceAll("table_name",
					selectOne.getSrcTables());
			map.put("srcScript", srcScript); // srcScript
			log.info("srcScript--->{}", srcScript);
			return;
		}

		if (null != mysqlinfo) {
			Server server = new Server();
			server.setServer(mysqlinfo.getHostIp());
			server.setUser("mysql");
			server.setPort(22);
			server.setPassword(mysqlinfo.getOsPasswd());
			map.put("srcServer", server); // srcServer
			log.info("srcServer:{}", server);
			// 整个实例迁移
			String path = mysqlinfo.getBackupDir();
			String srcScript = "mysqldump --single-transaction --set-gtid-purged=OFF --all-databases --triggers --routines --events >"+path+"all_databases.sql";
			// Schema迁移
			if (!StringUtils.isEmpty(selectOne.getSrcSchema())) {
				srcScript = "mysqldump --single-transaction --set-gtid-purged=OFF source_database >"+path+"/"+filename+".sql";
			}
			// Table迁移
			if (!StringUtils.isEmpty(selectOne.getSrcTables())) {
				srcScript = "mysqldump --single-transaction --set-gtid-purged=OFF source_database table_name >"+path+"/"+filename+".sql";
			}
			srcScript = srcScript.replaceAll("source_database", selectOne.getSrcSchema()).replaceAll("table_name",
					selectOne.getSrcTables());
			map.put("srcScript", srcScript); // srcScript
			log.info("srcScript--->{}", srcScript);
			return;
		}

	}

	private void setDestServerAndScript(CmSynOrder selectOne, Map<String, Object> map,String filename) {
		OracleInfo oracleinfo = getOracleInfo(selectOne.getDestInsName());
		MysqlInfo mysqlinfo = getMysqlInfo(selectOne.getDestInsName());
		if (null != oracleinfo) {
			Server server = new Server();
			server.setServer(oracleinfo.getHostIp());
			server.setUser("oracle");
			server.setPort(22);
			server.setPassword(oracleinfo.getOsPasswd());
			map.put("destServer", server);
			log.info("destServer:{}", server);
			// Schema迁移
			String destScript = "impdp \"userid='/ as sysdba'\" directory=exp_excel_dir  dumpfile="+oracleinfo.getBackupDir()+"/"+filename+".dmp remap_schema=source_schema:target_schema table_exists_action=type";
			if (!StringUtils.isEmpty(selectOne.getSrcTables())) {
				// Table迁移
				destScript = "impdp \"userid='/ as sysdba'\" directory=exp_excel_dir  dumpfile="+oracleinfo.getBackupDir()+"/"+filename+".dmp remap_schema=source_schema:target_schema table_exists_action=REPLACE";
				if ("yes".equalsIgnoreCase(selectOne.getType())) {// @TODO
					destScript = "impdp \"userid='/ as sysdba'\" directory=exp_excel_dir  dumpfile="+oracleinfo.getBackupDir()+"/"+filename+".dmp remap_schema=source_schema:target_schema remap_table=source_schema.table_name:target_table_name table_exists_action=APPEND";
				}
			}
			String type = "APPEND";
			if ("yes".equalsIgnoreCase(selectOne.getType()))
				type = "REPLACE";
			destScript = destScript.replaceAll("source_schema", selectOne.getSrcSchema())
					.replaceAll("target_schema", selectOne.getDestSchema()).replaceAll("type", type);
			map.put("destServer", destScript);
			log.info("destScript--->{}", destScript);
			return;
		}

		if (null != mysqlinfo) {
			Server server = new Server();
			server.setServer(mysqlinfo.getHostIp());
			server.setUser("mysql");
			server.setPort(22);
			server.setPassword(mysqlinfo.getOsPasswd());
			map.put("destServer", server); // srcServer
			log.info("destServer:{}", server);
			// 整个实例迁移
			String path = mysqlinfo.getBackupDir();
			String destScript = "mysql < "+path+"/"+filename+".sql";
			// Schema迁移
			if (!StringUtils.isEmpty(selectOne.getSrcSchema())) {
				destScript = "mysql target_database <"+path+"/"+filename+".sql";
			}
			// Table迁移
			if (!StringUtils.isEmpty(selectOne.getSrcTables())) {
				destScript = "mysql target_database <"+path+"/"+filename+".sql";
			}
			destScript = destScript.replaceAll("source_database", selectOne.getSrcSchema()).replaceAll("table_name",
					selectOne.getSrcTables()).replaceAll("target_database", selectOne.getDestSchema());
			map.put("destScript", destScript); // srcScript
			log.info("destScript--->{}", destScript);
			return;
		}

	}

	private void setSynServerAndScript(CmSynOrder selectOne, Map<String, Object> map,String filename) {
	
		OracleInfo oracleinfo = getOracleInfo(selectOne.getSrcInsName());
		MysqlInfo mysqlinfo = getMysqlInfo(selectOne.getSrcInsName());
		String synScript = "scp sfile username@hostip:dfile"; // TODO
		Server server = new Server();
		if (null != oracleinfo) {
			server.setServer(oracleinfo.getHostIp());
			server.setUser("oracle");
			server.setPort(22);
			server.setPassword(oracleinfo.getOsPasswd());
			map.put("synServer", server);
			synScript = synScript.replaceAll("sfile",oracleinfo.getBackupDir()+"/"+filename+".dmp");
		} else if (null != mysqlinfo) {
			server.setServer(mysqlinfo.getHostIp());
			server.setUser("mysql");
			server.setPort(22);
			server.setPassword(mysqlinfo.getOsPasswd());
			map.put("synServer", server);
			synScript = synScript.replaceAll("sfile",mysqlinfo.getBackupDir()+"/"+filename+".sql");
		}
		oracleinfo = getOracleInfo(selectOne.getDestInsName());
		mysqlinfo = getMysqlInfo(selectOne.getDestInsName());
		
		if (null != oracleinfo) {
			synScript = synScript.replaceAll("hostip", oracleinfo.getHostIp());
			synScript = synScript.replaceAll("username", "oracle");
			synScript = synScript.replaceAll("dfile",oracleinfo.getBackupDir());
			map.put("synServerPsw", oracleinfo.getOsPasswd());
			map.put("synScript", synScript);
		}
		if (null != mysqlinfo) {
			synScript = synScript.replaceAll("hostip", mysqlinfo.getHostIp());
			synScript = synScript.replaceAll("username", "mysql");
			synScript = synScript.replaceAll("dfile",mysqlinfo.getBackupDir());
			map.put("synServerPsw", mysqlinfo.getOsPasswd());
			map.put("synScript", synScript);
		}
		log.info("synScript:{}", synScript);
	}

	@Override
	public Map<String, Object> geneScripts(String busiNo) {
		Map<String, Object> map = new HashMap<>();
		CmSynOrder selectOne = getOrderByBusiNo(busiNo);
	    SimpleDateFormat sdf =new SimpleDateFormat("yyyyMMddHHmmss" );
	    Date currentTime= new Date();
	    String _currentTime = sdf.format(currentTime);
		setSrcServerAndScript(selectOne, map,_currentTime);
		setDestServerAndScript(selectOne, map,_currentTime);
		setSynServerAndScript(selectOne, map,_currentTime);
		return map;
	}

	private MysqlInfo getMysqlInfo(String insName) {
		QueryWrapper<MysqlInfo> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("ins_name", insName);
		queryWrapper.eq("role", "master");
		MysqlInfo mysqlinfo = mysqlInfoMapper.selectOne(queryWrapper);
		log.info("mysqlinfo----->{}", mysqlinfo);
		return mysqlinfo;
	}

	private OracleInfo getOracleInfo(String insName) {
		QueryWrapper<OracleInfo> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("ins_name", insName);
		// queryWrapper.eq("role","master");
		OracleInfo oracleinfo = oracleInfoMapper.selectOne(queryWrapper);
		log.info("oracleinfo----->{}", oracleinfo);
		return oracleinfo;
	}
	
	@Override
	public Map<String, Object> getDataInfo(String busiNo) {
		Map<String, Object> map = new HashMap<>();
		CmSynOrder selectOne = getOrderByBusiNo(busiNo);
		setDataInfoIntoMap(selectOne, map);
		return map;
	}
	
	private void setDataInfoIntoMap(CmSynOrder selectOne, Map<String, Object> map) {

		OracleInfo oracleinfo = getOracleInfo(selectOne.getSrcInsName());
		MysqlInfo mysqlinfo = getMysqlInfo(selectOne.getSrcInsName());
		if (null != oracleinfo) {
			oracleinfo.setOsPasswd("***");
			map.put("srcOracleInfo", oracleinfo);
			QueryWrapper<OraSegment> queryWrapper = new QueryWrapper<>();
	    	queryWrapper.eq("ins_name",selectOne.getSrcInsName()); //等值查询
	    	
	    	queryWrapper.eq("segment_type","TABLE"); //等值查询
	    	queryWrapper.in("segment_name",selectOne.getSrcTables().split(",")); //等值查询
	    	//SELECT * from ora_segment where ins_name = 'ctdb' and segment_type = 'TABLE' and segment_name = 'XDB$ATTRIBUTE';
			List<OraSegment> oracleTabInfos = oraSegmentMapper.selectList(queryWrapper);
			log.info(" ------>size:{}", oracleTabInfos.size());
			map.put("SrcOracleTableInfo", oracleTabInfos);
			
		}else if (null != mysqlinfo) {
			mysqlinfo.setOsPasswd("***");
			map.put("SrcMysqlInfo", mysqlinfo);
		}
		
		 oracleinfo = getOracleInfo(selectOne.getDestInsName());
		 mysqlinfo = getMysqlInfo(selectOne.getDestInsName());
		 if (null != oracleinfo) {
				map.put("DestOracleInfo", oracleinfo);
			}else if (null != mysqlinfo) {
				map.put("DestMysqlInfo", mysqlinfo);
			}
	}

}
